/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.epam.expertsys;

import java.util.*;

/**
 *
 * @author Admin
 */
public class Rule {

    private int numberUsedConditions;
    private ArrayList<Fact> conditions;
    private Set<String> usedVars;
    private Fact consequence;

    private Rule(ArrayList<Fact> conditions, Fact consequence) {
        this.usedVars = new HashSet<String>();
        this.conditions = (ArrayList<Fact>) conditions.clone();
        this.consequence = consequence.clone();
        this.numberUsedConditions = this.conditions.size();
        for (int index = 0; index < this.numberUsedConditions; index++) {
            this.usedVars.add(this.conditions.get(index).getVarName());
        }
    }

    /**
     *
     *
     * @param conditions - массив условий. Условия считываются до первой
     * null-ссылки в массиве; В случае, если таким образом не было считано
     * ни одного условия, конструктор бросает NullValueException
     * @param consequence - выводимое утверждение
     * @return 
     * @throws NullValueException
     * @throws VariableRedefinedException
     * @throws RepeatedConditionException
     */
    public static Rule create(ArrayList<Fact> conditions, Fact consequence)
            throws NullValueException, VariableRedefinedException,
            RepeatedConditionException {

        int conditionsCounter = 0;
        Set<String> usedVars = new HashSet<String>();
        ArrayList<Fact> tempConditions = new ArrayList<Fact>();


        if ((conditions == null) || (consequence == null)) {
            throw new NullValueException();
        }

        /*
         * TODO: можно сделать, чтобы целиком одинаковые кортежи не бросали
         * исключение, а игнориовались. Но это сильно дольше
         */
        for (int inCount = 0; inCount < conditions.size(); inCount++) {
            Fact currFact = conditions.get(inCount);
            if (currFact != null) {
                if (usedVars.contains(currFact.getVarName())) {
                    throw new RepeatedConditionException("Repeated condition "
                            + currFact.getVarName());
                }
                usedVars.add(currFact.getVarName());
                conditionsCounter++;
                tempConditions.add(currFact);
            }
        }

        if (conditionsCounter == 0) {
            throw new NullValueException();
        }

        if (usedVars.contains(consequence.getVarName())) {
            throw new VariableRedefinedException("Variable "
                    + consequence.getVarName() + " redefined");
        }

        return new Rule(tempConditions, consequence);

    }

    public Fact getCondition(int index) {
        return this.conditions.get(index);
    }

    public List<Fact> getConditons() {
        return (ArrayList<Fact>) this.conditions.clone();
    }

    public Fact getConsequence() {
        return this.consequence;
    }

    public boolean containsVariable(String varName) {
        return this.usedVars.contains(varName);
    }

    public int numConditions() {
        return this.numberUsedConditions;
    }
}
